import libtcodpy as libtcod
import math

# Object
# Description: a generic object representing a player, monster, item, stairs...
# That will always be represented by a char onscreen
#
# Attributes
#   x - the x coordinate of the object (int)
#   y - the y coordinate of the object (int)
#   char - how the object is displayed on screen (char)
#   color - the color of the object on screen (int)
#           Colors can be found in the libtcodpy library.
##
class Object:
    def __init__(self, x, y, char, name="", color=libtcod.BKGND_NONE,  blocks=False, fighter=None, ai=None, item=None, flammable=None):
        self.x = x
        self.y = y
        self.name = name
        self.char = char
        self.color = color
        self.blocks = blocks

        self.attributes = {}

        self.fighter = fighter
        # tell the components who owns them
        if self.fighter:
            self.fighter.owner = self
        self.ai = ai
        if self.ai:
            self.ai.owner = self
        self.item = item
        if self.item:
            self.item.owner = self
        self.flammable = flammable
        if self.flammable:
            self.flammable.owner = self



    def on_touch(self, toucher):

        for key in self.attributes:
            attr = self.attributes[key]

            if hasattr(attr, "on_touch"):
                attr.on_touch(toucher)

        return

    ##
    # move()
    # Description: move the object around by a given amount
    #
    # Parameters:
    #   map - the map to apply the move to.
    #   dx  - The difference in movement in the x direction.
    #         Negative values move left, positive values move right.(int)
    #   dy  - The difference in movement in the y direction.
    #         Negative values move up, positive values move down. (int)
    #
    # Returns: Boolean weather or not the move ocured
    ##
    def move(self, map, objects, dx, dy):

        newX = self.x + dx
        newY = self.y + dy
        if( newY < len(map[0]) and newY > -1 and newX < len(map) and newX > -1):

            map[newX][newY].touch_objects(self)

            if not self.is_block(map, objects, self.x + dx, self.y + dy):
                map[self.x][self.y].remove_object(self)

                self.x += dx
                self.y += dy

                map[self.x][self.y].add_object(self)


                return True
        return False

    def move_towards(self, map, objects, target_x, target_y):
        dx = target_x - self.x
        dy = target_y - self.y
        distance = math.sqrt(dx ** 2 + dy **2)

        dx = int(round(dx / distance))
        dy = int(round(dy / distance))
        self.move(map, objects, dx, dy)

    def distance_to(self, other):
        dx = other.x - self.x
        dy = other.y - self.y
        return math.sqrt(dx ** 2 + dy ** 2)

    def is_block(self, map, objects, x, y):
        # is the map tile available?
        if map[x][y].blocked:
            return True
        # is their an object on the tile?
        for object in map[x][y].stack:
            if object.blocks:
                return True
        return False

    ##
    # draw()
    # Description: Sets the color of the object and draws it to the console
    #
    #Parameters:
    #   con - the console you want the object to be drawn on. (libtcod.console_new())
    #
    # Returns: none
    ##
    def draw(self, con, fov_map):

        for key in self.attributes:
            attr = self.attributes[key]
            if hasattr(attr, "on_tick") and attr.on_tick is not None:
                attr.on_tick()

        if libtcod.map_is_in_fov(fov_map, self.x, self.y):
            # Set the color
            libtcod.console_set_default_foreground(con, self.color)

            # Draw the object to the console
            libtcod.console_put_char(con, self.x, self.y, self.char, libtcod.BKGND_NONE)

            for key in self.attributes:
                attr = self.attributes[key]
                if hasattr(attr, "draw") and attr.draw is not None:
                    attr.draw(con, fov_map)

    ##
    # clear()
    # Description: Erases the character that represents this object
    #Parameters:
    #   con - the console you want the object to be erased from. (libtcod.console_new())
    #
    # Returns: none
    ##
    def clear(self, con):
        libtcod.console_put_char(con, self.x, self.y, ' ', libtcod.BKGND_NONE)
